package com.synjones.wschool.face.serviceImpl;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.synjones.wschool.common.exception.BizException;
import com.synjones.wschool.common.util.DateUtil;
import com.synjones.wschool.face.constant.ModuleSourceEnum;
import com.synjones.wschool.face.constant.UserSourceEnum;
import com.synjones.wschool.face.domain.FaceInfo;
import com.synjones.wschool.face.domain.FileStorage;
import com.synjones.wschool.face.domain.GateInfoUser;
import com.synjones.wschool.face.mapper.GateInfoUserMapper;
import com.synjones.wschool.face.service.*;
import com.synjones.wschool.face.service.dto.UserDTO;
import com.synjones.wschool.face.service.request.GateInfoUserAddReq;
import com.synjones.wschool.face.service.request.GateInfoUserDelReq;
import com.synjones.wschool.face.service.request.GateInfoUserFaceReq;
import com.synjones.wschool.face.service.request.GateInfoUserListReq;
import com.synjones.wschool.face.service.response.FaceInfoMultiCheckResp;
import com.synjones.wschool.face.service.response.GateInfoUserVO;
import com.synjones.wschool.onecard.api.common.ResultResp;
import com.synjones.wschool.onecard.api.resp.ApiGetUserInfoResp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by 24398 on 2018/8/2.
 */
@Service
@Slf4j
public class GateInfoUserServiceImpl implements GateInfoUserService {

    @Resource
    private GateInfoUserMapper gateInfoUserMapper;
    @Resource
    private FaceInfoService faceInfoService;
    @Resource
    private EnoService enoService;
    @Resource
    private OneCardService oneCardService;
    @Resource
    private FileStorageService fileStorageService;

    @Value("${file.image.url.template}")
    private String FILE_PREFIX;

    private static final String DATETIME_FORMAT_DEFAULT = "yyyy-MM-dd HH:mm:ss";
    private static final String DATETIME_FORMAT_SHORT = "yyyy-MM-dd HH:mm";



    @Override
    @Transactional(rollbackFor = Exception.class)
    public void newGateInfo(GateInfoUserAddReq req) {
         req.checkParam();
         List<GateInfoUser> gateInfoUserList = new ArrayList<>();
         Date now = new Date();
         req.getInnerGateInfos().forEach(innerGateInfo -> {
             GateInfoUser gateInfoUser = new GateInfoUser();
             BeanUtils.copyProperties(innerGateInfo, gateInfoUser);
             gateInfoUser.setGmtCreate(now);
             gateInfoUserList.add(gateInfoUser);
         });

         String gateNO = req.getInnerGateInfos().get(0).getGateNO();
         // 查询数据库是否已经插入相应闸机编号检测人员类型数据  ，有替换
      /*  List<GateInfoUser> duplicatedGateInfoUsers = this.gateInfoUserMapper.selectList(gateInfoUserList);
        Iterator<GateInfoUser> gateInfoIterator = gateInfoUserList.iterator();
        while(gateInfoIterator.hasNext()){
            GateInfoUser gateInfoUserAdd = gateInfoIterator.next();
            boolean flag = duplicatedGateInfoUsers.parallelStream().anyMatch(gateInfoUser -> gateInfoUser.getGateNO().equals(gateInfoUserAdd.getGateNO())
                                                                         && gateInfoUser.getUserSourceId().equals(gateInfoUserAdd.getUserSourceId()));

            if(flag){
              gateInfoIterator.remove();
            }

        }*/
        List<GateInfoUser> oldGateInfoUsers = this.gateInfoUserMapper.listByGateNO(gateNO);
        if(oldGateInfoUsers != null && oldGateInfoUsers.size() > 0){
            // 删除old数据
           int n =     this.gateInfoUserMapper.delete(gateNO);
           if(n != oldGateInfoUsers.size()){
               log.error("更新闸机信息失败： [{}]","删除旧的闸机信息失败");
               throw new  BizException("删除旧的闸机信息失败");
           }
        }

        // 插入数据库
        if(gateInfoUserList.size() > 0){
            this.gateInfoUserMapper.batchSave(gateInfoUserList);
        }

    }

    @Override
    public void delGateInfo(GateInfoUserDelReq req) {
        String gateNO = req.getGateNO();
        this.gateInfoUserMapper.delete(gateNO);
    }


    @Override
    public List<FaceInfoMultiCheckResp> listCheckedFaceInfo(GateInfoUserFaceReq req) {
        req.checkParam();
        Date date = req.getDate();
        // 查询gate_info_user 数据
        List<GateInfoUser> gateInfoUsers = this.gateInfoUserMapper.listByGateNO(req.getGateNO());
        if(gateInfoUsers == null || gateInfoUsers.isEmpty()){
            log.error("拉取人脸检测数据失败：[{}]","没有查到闸机信息");
            throw new BizException("没有查到闸机信息");
        }

        List<Integer> userSourceIds = gateInfoUsers.parallelStream().map(GateInfoUser::getUserSourceId).collect(Collectors.toList());

        boolean successChecked  = true;
        List<FaceInfo> faceInfos =  this.faceInfoService.listCheckedFaceInfo(date,userSourceIds,successChecked);
        if(faceInfos == null || faceInfos.isEmpty()){
            return Collections.emptyList();
        }
        // 查询图片
        List<Long> faceInfoIds = faceInfos.parallelStream().map(FaceInfo::getId).collect(Collectors.toList());
        List<FileStorage> fileStorages = this.fileStorageService.selectList(faceInfoIds, ModuleSourceEnum.FACE_INFO.getSourceId());
        Table<Long,Integer,String> fileUrlsTable = HashBasedTable.create();
        fileStorages.forEach(fileStorage -> {
            fileUrlsTable.put(fileStorage.getFileSourceId(),fileStorage.getFileSourceType(),String.format(FILE_PREFIX,fileStorage.getUrl()));
        });


        // 查询检测用户一卡通号，暂时是教师
           // 查询学工号
        List<UserDTO> userDTOS = faceInfos.parallelStream().map(faceInfo -> UserDTO.builder()
                                                                  .userId(faceInfo.getTeacherId())
                                                                  .userSourceId(faceInfo.getUserSourceId())
                                                                  .build()).collect(Collectors.toList());

        List<UserDTO> userDTOSWithEno = this.enoService.listEno(userDTOS);
        if(userDTOSWithEno == null || userDTOSWithEno.size() != userDTOS.size()){
            log.error("拉取人脸检测数据失败：[{}]","查询人脸识别用户出错");
            throw new BizException("查询人脸识别用户出错");
        }
             // 查询一卡通信息
        List<String> enos = userDTOSWithEno.parallelStream().map(UserDTO::getEno).collect(Collectors.toList());
        log.info("enos   : [{}]",enos);
        ResultResp<List<ApiGetUserInfoResp>> resultResp = this.oneCardService.batchGetUserInfo(enos);
        if(!resultResp.isResult()){
            log.error("拉取人脸检测数据失败: [{}]",resultResp.getMsg());
            throw new BizException(resultResp.getMsg());
        }

        List<ApiGetUserInfoResp> apiGetUserInfoResps = resultResp.getData();
     //   log.info("apiGetUserInfoResps : [{}]",apiGetUserInfoResps);
        Map<String,String> enoCardNoMap = apiGetUserInfoResps.parallelStream().collect(Collectors.toMap(ApiGetUserInfoResp::getSno,
                                                                     ApiGetUserInfoResp::getCardNo ));


        // 组装数据

        List<FaceInfoMultiCheckResp> faceInfoMultiCheckResps = new ArrayList<>();
        faceInfos.forEach(faceInfo -> {
            FaceInfoMultiCheckResp faceInfoMultiCheckResp = new FaceInfoMultiCheckResp();

            UserDTO userDTO = this.getUserDTO(faceInfo.getTeacherId(),faceInfo.getUserSourceId(),userDTOSWithEno);
            if(userDTO == null){
                userDTO = new UserDTO();
            }
            faceInfoMultiCheckResp.setUserName(userDTO.getUserName());
            faceInfoMultiCheckResp.setUserNumber(userDTO.getEno());
            faceInfoMultiCheckResp.setCreateTime(DateUtil.date2Str(faceInfo.getGmtCreate(),DATETIME_FORMAT_DEFAULT));
            faceInfoMultiCheckResp.setCardNumber(enoCardNoMap.get(userDTO.getEno()));
      //      faceInfoMultiCheckResp.setCardNumber("");
            faceInfoMultiCheckResp.setImageUrl(fileUrlsTable.get(faceInfo.getId(),ModuleSourceEnum.FACE_INFO.getSourceId()));
            faceInfoMultiCheckResp.setBeValid(faceInfo.getValidStatus());
            faceInfoMultiCheckResps.add(faceInfoMultiCheckResp);
        });

        return faceInfoMultiCheckResps;
    }



    private UserDTO getUserDTO(Long userId,Integer userSourceId,List<UserDTO> userDTOS){
        UserDTO userDTO = userDTOS.parallelStream().filter(userDTO1 -> userDTO1.getUserId().equals(userId) &&
                                                                 userDTO1.getUserSourceId().equals(userSourceId))
                                                     .findFirst().orElse(null);


        return userDTO;
    }

    @Override
    public List<GateInfoUserVO> listGateInfoUser(GateInfoUserListReq gateInfoUserListReq) {
        List<GateInfoUser> gateInfoUsers = this.gateInfoUserMapper.listGateInfoUser();
        if(gateInfoUsers == null || gateInfoUsers.isEmpty()){
            return Collections.emptyList();
        }
        List<GateInfoUserVO> gateInfoUserVOS = new ArrayList<>();

        gateInfoUsers.forEach(gateInfoUser -> {
            GateInfoUserVO gateInfoUserVO = new GateInfoUserVO();
            BeanUtils.copyProperties(gateInfoUser,gateInfoUserVO);
            gateInfoUserVO.setUserSources(new ArrayList<>());

            List<Integer> userSourceIds = gateInfoUsers.parallelStream()
                    .filter(gateInfoUser1 -> gateInfoUser1.getGateNO().equals(gateInfoUser.getGateNO()))
                     .map(GateInfoUser::getUserSourceId)
                      .collect(Collectors.toList());

            userSourceIds.forEach(userSourceId ->{
                String userSourceDesc = InnerUserSourceEnum.getUserDesc(userSourceId);
                gateInfoUserVO.getUserSources().add(userSourceDesc);
            });

            gateInfoUserVOS.add(gateInfoUserVO);

        });

        List<GateInfoUserVO> ret = gateInfoUserVOS.parallelStream().distinct().collect(Collectors.toList());

        return ret;
    }


     enum  InnerUserSourceEnum{

         TEACHER(1,"教师"),

         GUARDIAN(2,"监护人"),

         STUDENT(3,"学生"),

         OPERATOR(4,"操作员");


         private Integer userSourceId;
         private String  desc;

         private    InnerUserSourceEnum(Integer userSourceId,String desc) {
             this.userSourceId = userSourceId;
             this.desc = desc;
         }

         public Integer getUserSourceId() {
             return userSourceId;
         }

         public String getDesc(){return  desc;}

         public static String  getUserDesc(Integer userSourceId){
             InnerUserSourceEnum [] innerUserSourceEnums = InnerUserSourceEnum.values();
             for(int i =0;i< innerUserSourceEnums.length;i++){
                 InnerUserSourceEnum innerUserSourceEnum = innerUserSourceEnums[i];
                 if(innerUserSourceEnum.getUserSourceId().equals(userSourceId)){
                     return innerUserSourceEnum.getDesc();
                 }
             }


             return "";
         }


    }

}
